#include "GUIListBox.h"
#include "GUIListBoxItem.h"
#include "IRenderer.h"
#include "OnMouseLeftDownEvent.h"

GUIListBox::GUIListBox()
{
	m_fontColor = 0xFF000000;
	m_font = HashedString("Arial");
	m_selectedIndex = -1;
}

void GUIListBox::Paint()
{
	if (m_visible)
	{
		unsigned int totalHeight = 0;
		Maths::Matrix transform;

		// Render ListItems
		transform.Identity();
		transform.Translate(m_location.X, m_location.Y, 0.0f);		// Add OBJECTHEIGHT to Y for title
		Renderer->PushModelViewMatrix(transform);
		
		for (int i = 0; i < m_listItems.size(); ++i)
		{
			GUIListBoxItem* item = m_listItems[i];

			item->Location(Maths::Point<unsigned int>(0, totalHeight));
			if (i == m_selectedIndex)
			{
				Renderer->PrintFont(m_font, m_fontColor, m_parentLocation.X + m_location.X + 10, m_parentLocation.Y + m_location.Y + totalHeight + 6, "*"); 
			}
			item->Paint();
			totalHeight += 22;
		}

		Renderer->PopModelViewMatrix();
	}
}
bool GUIListBox::ReceiveEvent( IEvent& event )
{
	if (m_enabled && m_visible)
	{
		if (event.Type() == OnMouseLeftDownEvent::type)
		{
			OnMouseLeftDownEvent& mouseEvent = static_cast<OnMouseLeftDownEvent&>(event);
			int x = mouseEvent.Coords().X;
			int y = mouseEvent.Coords().Y;
			int absX = m_location.X + m_parentLocation.X;
			int absY = m_location.Y + m_parentLocation.Y;
			int greatestWidth = m_dimensions.X;
			int totalHeight = m_listItems.size() * 22;
			int indent = 0;
			// for every menu object
			for (GUIListBoxItem::Vector_t::const_iterator it = m_listItems.begin(); it != m_listItems.end(); ++it)
			{
				if (greatestWidth < (*it)->Dimensions().X)
					greatestWidth = (*it)->Dimensions().X;
			}

			if ((x > absX) && (x < absX + greatestWidth) &&
				(y > absY) && (y < absY + totalHeight))						// not title clicked
			{
				for (GUIListBoxItem::Vector_t::iterator it = m_listItems.begin(); it != m_listItems.end(); ++it)
				{
					if ((*it)->ReceiveEvent(event))
						return true;
				}
			}
		}
	}
	return false;
}

void GUIListBox::AddListBoxItem( Pointer<GUIListBoxItem>& item )
{
	m_listItems.push_back(item);
	item->Parent(this);
	item->ParentLocation(Maths::Point<unsigned int>(m_location.X + m_parentLocation.X + 15, m_location.Y + m_parentLocation.Y));
}
void GUIListBox::ClearListBoxItems()
{
	m_listItems.clear();
	m_selectedIndex = -1;
}
void GUIListBox::RemoveListBoxItem( unsigned int itemIndex )
{
	m_listItems.erase(m_listItems.begin() + itemIndex);
	if (m_selectedIndex > m_listItems.size())
		m_selectedIndex = m_listItems.size();
}
void GUIListBox::RemoveSelected()
{
	if (m_selectedIndex != -1)
	{
		m_listItems.erase(m_listItems.begin() + m_selectedIndex);
		--m_selectedIndex;
	}
}

void GUIListBox::OnSelectedChangedFunction( Pointer<Functor>& function )
{
	m_onSelectedChangedFunction = function;
}
void GUIListBox::Select( GUIListBoxItem* item )
{
	for (int i = 0; i < m_listItems.size(); ++i)
	{
		GUIListBoxItem* ptr = m_listItems[i];
		if (ptr == item)
		{
			m_selectedIndex = i;
			if (m_onSelectedChangedFunction.isValid())
				(*m_onSelectedChangedFunction)();
			return;
		}
	}
	m_selectedIndex = -1;
	return;
}
void GUIListBox::Select( unsigned int select )
{
	if (select < m_listItems.size())
	{
		m_selectedIndex = select;
		if (m_onSelectedChangedFunction.isValid())
			(*m_onSelectedChangedFunction)();
	} else 
	{
		m_selectedIndex = -1;
	}
}
unsigned int GUIListBox::SelectedRow() const
{
	return m_selectedIndex;
}
Pointer<GUIListBoxItem> GUIListBox::Selected() const
{
	if (m_selectedIndex == -1)
		return Pointer<GUIListBoxItem>(0);
	return m_listItems[m_selectedIndex];
}
void GUIListBox::ParentLocation(Maths::Point<unsigned int>& location)
{
	IGUIElement::ParentLocation(location);
	for (GUIListBoxItem::Vector_t::const_iterator it = m_listItems.begin(); it != m_listItems.end(); ++it)
		(*it)->ParentLocation(Maths::Point<unsigned int>(m_location.X + m_parentLocation.X + 15, m_location.Y + m_parentLocation.Y));
}
void GUIListBox::Location(Maths::Point<unsigned int>& location)
{
	IGUIElement::Location(location);
	for (GUIListBoxItem::Vector_t::const_iterator it = m_listItems.begin(); it != m_listItems.end(); ++it)
		(*it)->ParentLocation(Maths::Point<unsigned int>(m_location.X + m_parentLocation.X + 15, m_location.Y + m_parentLocation.Y));
}